package com.swak.fx.support.transition;

import java.util.function.Supplier;

import javafx.animation.Interpolator;
import javafx.beans.value.WritableValue;

public class UIKeyValue<T> {

	private WritableValue<T> target;
	private Supplier<WritableValue<T>> targetSupplier;
	private Supplier<T> endValueSupplier;
	private T endValue;
	private Supplier<Boolean> animateCondition = () -> true;
	private Interpolator interpolator;

	private UIKeyValue() {
	}

	// this builder is created to ensure type inference from method arguments
	public static Builder builder() {
		return new Builder();
	}

	public T getEndValue() {
		return endValue == null ? endValueSupplier.get() : endValue;
	}

	public WritableValue<T> getTarget() {
		return target == null ? targetSupplier.get() : target;
	}

	public Interpolator getInterpolator() {
		return interpolator;
	}

	public boolean isValid() {
		return animateCondition == null ? true : animateCondition.get();
	}

	public static final class Builder {
		public <T> UIKeyValueBuilder<T> setTarget(WritableValue<T> target) {
			UIKeyValueBuilder<T> builder = new UIKeyValueBuilder<>();
			builder.setTarget(target);
			return builder;
		}

		public <T> UIKeyValueBuilder<T> setTargetSupplier(Supplier<WritableValue<T>> targetSupplier) {
			UIKeyValueBuilder<T> builder = new UIKeyValueBuilder<>();
			builder.setTargetSupplier(targetSupplier);
			return builder;
		}

		public <T> UIKeyValueBuilder<T> setEndValueSupplier(Supplier<T> endValueSupplier) {
			UIKeyValueBuilder<T> builder = new UIKeyValueBuilder<>();
			builder.setEndValueSupplier(endValueSupplier);
			return builder;
		}

		public <T> UIKeyValueBuilder<T> setEndValue(T endValue) {
			UIKeyValueBuilder<T> builder = new UIKeyValueBuilder<>();
			builder.setEndValue(endValue);
			return builder;
		}

		public <T> UIKeyValueBuilder<T> setAnimateCondition(Supplier<Boolean> animateCondition) {
			UIKeyValueBuilder<T> builder = new UIKeyValueBuilder<>();
			builder.setAnimateCondition(animateCondition);
			return builder;
		}

		public <T> UIKeyValueBuilder<T> setInterpolator(Interpolator interpolator) {
			UIKeyValueBuilder<T> builder = new UIKeyValueBuilder<>();
			builder.setInterpolator(interpolator);
			return builder;
		}
	}

	public static final class UIKeyValueBuilder<T> {

		private WritableValue<T> target;
		private Supplier<WritableValue<T>> targetSupplier;
		private Supplier<T> endValueSupplier;
		private T endValue;
		private Supplier<Boolean> animateCondition = () -> true;
		private Interpolator interpolator = Interpolator.EASE_BOTH;

		private UIKeyValueBuilder() {
		}

		public UIKeyValueBuilder<T> setTarget(WritableValue<T> target) {
			this.target = target;
			return this;
		}

		public UIKeyValueBuilder<T> setTargetSupplier(Supplier<WritableValue<T>> targetSupplier) {
			this.targetSupplier = targetSupplier;
			return this;
		}

		public UIKeyValueBuilder<T> setEndValueSupplier(Supplier<T> endValueSupplier) {
			this.endValueSupplier = endValueSupplier;
			return this;
		}

		public UIKeyValueBuilder<T> setEndValue(T endValue) {
			this.endValue = endValue;
			return this;
		}

		public UIKeyValueBuilder<T> setAnimateCondition(Supplier<Boolean> animateCondition) {
			this.animateCondition = animateCondition;
			return this;
		}

		public UIKeyValueBuilder<T> setInterpolator(Interpolator interpolator) {
			this.interpolator = interpolator;
			return this;
		}

		public UIKeyValue<T> build() {
			UIKeyValue<T> UIKeyValue = new UIKeyValue<>();
			UIKeyValue.target = this.target;
			UIKeyValue.interpolator = this.interpolator;
			UIKeyValue.targetSupplier = this.targetSupplier;
			UIKeyValue.endValue = this.endValue;
			UIKeyValue.endValueSupplier = this.endValueSupplier;
			UIKeyValue.animateCondition = this.animateCondition;
			return UIKeyValue;
		}
	}
}
